package com.kwok.rbac.application.common.aop.annotation.aspect;

import com.kwok.rbac.application.common.aop.annotation.AccessPrivilege;
import com.kwok.rbac.application.common.security.SystemUserTokenThreadLocal;
import com.kwok.rbac.application.entity.Privilege;
import com.kwok.rbac.application.entity.SystemUserToken;
import com.kwok.rbac.application.exception.NoPrivilegeException;
import com.kwok.rbac.application.service.PrivilegeService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @Aspect表示PrivilegeAspect是一个切面类
 * @Component表示把PrivilegeAspect这个Bean(java类)交给IOC容器管理
 */
@Aspect
@Component
public class PrivilegeAspect {

    @Autowired
    private PrivilegeService privilegeService;

    //使用环绕通知校验是否有权限进行调用打了@AccessPrivilege注解的接口
    //满足条件(加了AOP自定义注解@AccessPrivilege)的方法被调用时才会进入checkPrivilege方法
    @Around(value = "@annotation(accessPrivilege)")
    public Object checkPrivilege(ProceedingJoinPoint proceedingJoinPoint, AccessPrivilege accessPrivilege) throws Throwable {
        System.out.println("环绕通知开始");
        //1.获取当前登录用户拥有的权限
        SystemUserToken systemUserToken = SystemUserTokenThreadLocal.get();
        Integer userId = systemUserToken.getUserId();
        //2.根据用户id查询该用户有哪些权限
        List<Privilege> privilegeList = privilegeService.getPrivilegeByUserId(userId);
        //3.遍历装权限的集合，判断权限信息（权限是否匹配接口的权限码）
        Boolean flag = false;
        for (Privilege privilege : privilegeList) {
            if (privilege.getPrivilegeMessage().equals(accessPrivilege.value())){
                //4.判断当前用户是否有权限访问该方法(进入这里说明有权限访问)
                flag = true;
                break;
            }

            if (!flag){
                //5.没有权限访问，抛出自定义异常
                throw new NoPrivilegeException(3333,"当前用户没有权限访问该方法接口");
            }
        }

        //调用目标方法
        Object proceed = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        System.out.println("环绕通知结束");
        return proceed;
    }

}
